﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

// Qt headers
#include <QEvent>
#include <QMouseEvent>
#include <QDir>
#include <QPainter>
#include <QApplication>

//gcmp headers
#include "GcmpModel.h"
#include "JournalUtils.h"

// custom headers
#include "ProjectComponentItemDelegate.h"
#include "ProjectComponentsTableSymbols.h"
#include "IProjectComponent.h"
#include "PaintingUtils.h"
#include "UIService.h"
#include "AppService.h"
#include "ProjectLoadedComponentService.h"
#include "PermissionWatcher.h"
#include "Permission.h"
#include "GmepLocalDbService.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

namespace gmepgcs 
{
    ProjectComponentItemDelegate::ProjectComponentItemDelegate(QWidget *parent) :
        QStyledItemDelegate(parent),
        m_parentWidget(parent),
        m_isEditOperationVisible(true)
    {
    }
    
    ProjectComponentItemDelegate::~ProjectComponentItemDelegate()
    {

    }

    void ProjectComponentItemDelegate::SetIsEditOperationVisible(bool isEditOperationVisible /*= true*/)
    {
        m_isEditOperationVisible = isEditOperationVisible;
    }
    void ProjectComponentItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
    {
        DBG_WARN_AND_RETURN_VOID_UNLESS(painter != nullptr, L"painter为空", L"GMEP", L"2024-01-30");
        const QAbstractItemModel * indexModel = index.model();
        DBG_WARN_AND_RETURN_VOID_UNLESS(indexModel != nullptr, L"indexModel为空", L"GMEP", L"2024-01-30");
        // draw bottom line
        painter->save();
        painter->setPen(QPen(QColor(189, 199, 213), 1.0)); // #BDC7D5
        painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
        painter->restore();

        QFont font;
        font.setFamily("Microsoft YaHei");
        font.setPixelSize(12);

        int32_t col = index.column();

        if (col == COL_CHECKBOX)
        {            
            if (!m_isEditOperationVisible)
            {
                // draw selected style
                if (option.state & QStyle::State_Selected)
                {
                    painter->save();
                    painter->fillRect(option.rect, QBrush(QColor(41, 121, 255, 34), Qt::BrushStyle::SolidPattern));
                    painter->restore();
                }
                return;
            }
            // draw checkbox
            int32_t boxExtent = 12;
            QPoint boxOffset((option.rect.width() - boxExtent) / 2, (option.rect.height() - boxExtent) / 2);
            QRect boxRect(option.rect.topLeft() + boxOffset, QSize(boxExtent, boxExtent));            
            bool isChecked = indexModel->data(index, Qt::UserRole).toBool();
            if (isChecked)
            {
                PaintingUtils::DrawBorder(painter, boxRect, QMargins(1, 1, 1, 1), QMargins(2, 2, 2, 2), QColor(82, 145, 221, 255), QColor(82, 145, 221, 255));

                QRect tickRect = boxRect.marginsAdded(QMargins(-2, -2, -2, -2));
                QImage tickImage = QImage(":/images/icon_tick_ffffff_12.png");
                painter->setRenderHint(QPainter::RenderHint::SmoothPixmapTransform);
                painter->drawPixmap(tickRect, QPixmap::fromImage(tickImage));
            }
            else
            {
                PaintingUtils::DrawBorder(painter, boxRect, QMargins(1, 1, 1, 1), QMargins(2, 2, 2, 2), QColor(189, 199, 213, 255));
            }

            // draw selected style
            if (option.state & QStyle::State_Selected)
            {
                painter->save();
                painter->fillRect(option.rect, QBrush(QColor(41, 121, 255, 34), Qt::BrushStyle::SolidPattern));
                painter->restore();
            }
        }
        else if (col == COL_COMPONENT_NAME)
        {
            // draw thumbnail
            QMargins iconMargin(10, 5, 0, 5);
            QMargins iconBorder(1, 1, 1, 1);
            int32_t iconExtent= option.rect.height() - iconMargin.top() - iconMargin.bottom();
            QSize iconSize(iconExtent, iconExtent);
            QPoint iconOffset(iconMargin.left(), iconMargin.top());
            QRect iconRect(option.rect.topLeft() + iconOffset, iconSize);
            painter->save();
            painter->setBrush(Qt::BrushStyle::NoBrush);
            painter->setPen(QPen(QColor(189, 199, 213), iconBorder.left()));
            painter->drawLine(iconRect.bottomLeft(), iconRect.topLeft());
            painter->setPen(QPen(QColor(189, 199, 213), iconBorder.top()));
            painter->drawLine(iconRect.topLeft(), iconRect.topRight());
            painter->setPen(QPen(QColor(189, 199, 213), iconBorder.right()));
            painter->drawLine(iconRect.topRight(), iconRect.bottomRight());
            painter->setPen(QPen(QColor(189, 199, 213), iconBorder.bottom()));
            painter->drawLine(iconRect.bottomRight(), iconRect.bottomLeft());
            painter->restore();
            QIcon icon = indexModel->data(index, Qt::DecorationRole).value<QIcon>();
            if (!icon.isNull())
            {
                QPixmap iconPixmap = icon.pixmap(iconSize);
                painter->drawPixmap(iconRect.adjusted(1, 1, -1, -1), iconPixmap);
            }
            
            // draw dot mark
            IProjectComponent *component = static_cast<IProjectComponent*>(index.internalPointer());

            bool isComponentUpdatable = false;
            
            if (!component)
            {
                isComponentUpdatable = false;
            }
            else
            {
                isComponentUpdatable = component->IsReleased() && (component->GetIsSyncable() || component->GetIsUpdatable());
            }

            if (isComponentUpdatable)
            {
                painter->save();
                painter->setRenderHint(QPainter::RenderHint::Antialiasing);
                painter->setBrush(QBrush(QColor(255, 110, 110)));
                painter->setPen(QPen(QColor(255, 110, 110)));
                float radius = 3.5;
                QPointF center = iconRect.topRight() + QPointF(0, radius);
                painter->drawEllipse(center, radius, radius);
                painter->restore();
            }
            
            // draw text
            QMargins textMargin(5, 0, 0, 0);
            QPoint textOffset(iconOffset.x() + iconSize.width() + iconMargin.right() + textMargin.left(), textMargin.top());
            QRect textRect(option.rect.topLeft() + textOffset, option.rect.bottomRight());
            QString text = indexModel->data(index, Qt::DisplayRole).value<QString>();
            painter->save();
            painter->setFont(font);
            QColor textColor = QColor("#282833");
            if (isComponentUpdatable)
            {
                textColor = QColor(87, 154, 222, 255);
            }
            painter->setPen(QPen(textColor, 1.0));
            QTextOption textOption(option.displayAlignment);
            textOption.setWrapMode(QTextOption::WrapMode::NoWrap);
            painter->drawText(textRect, text, textOption);
            painter->restore();
            
            // draw selected style
            if (option.state & QStyle::State_Selected)
            {
                painter->save();
                painter->fillRect(option.rect, QBrush(QColor(41, 121, 255,34), Qt::BrushStyle::SolidPattern));
                painter->restore();
            }
        }
        else if (
            col == COL_COMPONENT_OPERARION_SYNC ||
            col == COL_COMPONENT_OPERARION_PLACE ||
            col == COL_COMPONENT_OPERARION_LOADINTO ||
            col == COL_COMPONENT_OPERARION_DELETE)
        {
            // draw text
            QString text = indexModel->data(index, Qt::DisplayRole).value<QString>();
            if (!text.isEmpty())
            {
                painter->save();
                painter->setFont(font);
                QColor textColor = indexModel->data(index, Qt::ItemDataRole::TextColorRole).value<QColor>();
                if (text == "删除" && (PermissionWatcher::Get()->GetCurrentPermission() == Permission::SOFTWRITE))
                {
                    textColor = QColor(120, 122, 131, 255);
                }
                QPalette palette = QApplication::palette();
                palette.setColor(QPalette::ColorRole::Foreground, textColor);
                painter->setPen(QPen(textColor, 1.0));
                int textAlignment = indexModel->data(index, Qt::ItemDataRole::TextAlignmentRole).value<int>();
                QTextOption textOption((Qt::AlignmentFlag)textAlignment);
                textOption.setWrapMode(QTextOption::WrapMode::NoWrap);
                painter->drawText(option.rect, text, textOption);
                painter->restore();
            }

            // draw selected style
            if (option.state & QStyle::State_Selected)
            {
                painter->save();
                painter->fillRect(option.rect, QBrush(QColor(41, 121, 255, 34), Qt::BrushStyle::SolidPattern));
                painter->restore();
            }
        }
    }

    bool ProjectComponentItemDelegate::editorEvent(QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index)
    {
        if (!index.isValid() || !model)
        {
            return false;
        }

        IProjectComponent *component = static_cast<IProjectComponent *>(index.internalPointer());
        if (!component)
        {
            return false;
        }

        if (!m_parentWidget)
        {
            return QStyledItemDelegate::editorEvent(event, model, option, index);
        }

        m_parentWidget->setCursor(Qt::ArrowCursor);
        m_parentWidget->setToolTip(QString());

        int32_t col = index.column();
        QMouseEvent *mouseEvent = dynamic_cast<QMouseEvent*>(event);

        if (col == COL_CHECKBOX)
        {
            if (event->type() == QEvent::MouseButtonPress && mouseEvent!=nullptr && option.rect.contains(mouseEvent->pos()))
            {
                QModelIndex fixedColumeIndex = model->index(index.row(), COL_COMPONENT_OPERARION_PLACE, index.parent());
                const QAbstractItemModel* pfixedColumeIndexModel = fixedColumeIndex.model();
                if (!pfixedColumeIndexModel)
                    return false;
                QString text = pfixedColumeIndexModel->data(index, Qt::DisplayRole).value<QString>();

                bool isChecked = model->data(index, Qt::UserRole).toBool();
                model->setData(index, !isChecked, Qt::UserRole);
                return true;
            }            
        }
        else if (
            col == COL_COMPONENT_OPERARION_SYNC ||
            col == COL_COMPONENT_OPERARION_PLACE || 
            col == COL_COMPONENT_OPERARION_LOADINTO ||
            col == COL_COMPONENT_OPERARION_DELETE)
        {
            if (mouseEvent)
            {
                const QAbstractItemModel * indexModel = index.model();
                if (!indexModel)
                {
                    return false;
                }
                QString text = indexModel->data(index, Qt::DisplayRole).value<QString>();
                int textAlignment = indexModel->data(index, Qt::TextAlignmentRole).value<int>();
                QFont font = QApplication::font();
                QRect textRect = PaintingUtils::GetTextRect(option.rect, text, font, textAlignment);
                QRect mouseCaptureRect(textRect.topLeft(), QSize(textRect.width(), option.rect.height()));
                mouseCaptureRect.adjust(0, 1, 0, -1);

                if (gcmp::JournalUtils::IsInReplay())
                {
                    mouseCaptureRect = option.rect;
                }

                if (mouseCaptureRect.contains(mouseEvent->pos()))
                {
                    if (text == "删除" && (PermissionWatcher::Get()->GetCurrentPermission() == Permission::SOFTWRITE))
                    {
                        m_parentWidget->setToolTip(QString::fromStdWString(GBMP_TR(L"示例项目中无该功能权限")));
                        return QStyledItemDelegate::editorEvent(event, model, option, index);
                    }

                    m_parentWidget->setCursor(Qt::PointingHandCursor);

                    if (event->type() == QEvent::MouseButtonPress)
                    {
                        HandleOperation(model, index);
                        return true;
                    }
                }
            }
        }

        return QStyledItemDelegate::editorEvent(event, model, option, index);
    }

    void ProjectComponentItemDelegate::HandleOperation(QAbstractItemModel *model, const QModelIndex &index)
    {
        IProjectComponent *component = static_cast<IProjectComponent *>(index.internalPointer());

        if (component)
        {
            const QAbstractItemModel * pModel = index.model();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pModel != nullptr, L"pModel为空", L"GMEP", L"2024-01-30");
            QString text = pModel->data(index, Qt::DisplayRole).value<QString>();
            if (text == QString::fromStdWString(GBMP_TR(L"布置")))
            {
                emit PlaceComponentRequired(model, index);
            }
            else if (text == QString::fromStdWString(GBMP_TR(L"同步")))
            {
                emit SyncComponentRequired(model, index);
            }
            else if (text == QString::fromStdWString(GBMP_TR(L"载入")))
            {
                emit LoadComponentRequired(model, index);
            }
            else if (text == QString::fromStdWString(GBMP_TR(L"删除")))
            {
                emit DeleteComponentRequired(model, index);
            }
        }
    }
}
